#include "assert.h" 
#include "../../include/MathUtil/Vector.h"
#include <cmath>
#include <iostream>

using namespace z_vector;

	Vector3f::Vector3f() :x(0.0f), y(0.0f), z(0.0f) {}

	Vector3f::Vector3f(float x, float y, float z) :x(x), y(y), z(z) {}

	Vector3f::Vector3f(const Vector3f& vec) : x(vec.x), y(vec.y), z(vec.z) {}

	Vector3f::Vector3f(const Vector2f& vec, float z): x(vec.x), y(vec.y), z(z) {}

	Vector3f::~Vector3f(){}

	
	Vector3f Vector3f::operator+(const Vector3f& vec)
	{
		return Vector3f(this->x + vec.x, this->y + vec.y, this->z + vec.z);
	}

	Vector3f Vector3f::operator-(const Vector3f& vec)
	{
		return Vector3f(this->x - vec.x, this->y - vec.y, this->z - vec.z);
	}

	Vector3f Vector3f::operator*(const Vector3f& vec)
	{
		return Vector3f(this->x * vec.x, this->y * vec.y, this->z * vec.z);
	}

	Vector3f Vector3f::operator/(const Vector3f& vec)
	{
		assert(vec.x != 0.0 && vec.y != 0.0 && vec.z != 0.0);
		return Vector3f(this->x / vec.x, this->y / vec.y, this->z / vec.z);
	}

	Vector3f Vector3f::operator*(float k)
	{
		return Vector3f(this->x * k, this->y * k, this->z * k);
	}

	Vector3f Vector3f::operator/(float k)
	{
		assert(k != 0);
		return Vector3f(this->x / k, this->y / k, this->z / k);
	}

	Vector3f Vector3f::operator+()
	{
		return *this;
	}

	Vector3f Vector3f::operator-()
	{
		return Vector3f(-this->x, -this->y, -this->z);
	}

	float Vector3f::Dot(const Vector3f& v2)
	{
		Vector3f& v1 = *this;
		return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
	}

	Vector3f Vector3f::Product(const Vector3f& v2)
	{
		Vector3f& v1 = *this;
		float xTerm = v1.y * v2.z - v1.z * v2.y;
		float yTerm = v2.x * v1.z - v1.x * v2.z;
		float zTerm = v1.x * v2.y - v2.x * v1.y;
		return Vector3f(xTerm, yTerm, zTerm);
	}

	float z_vector::Vector3f::Magnitude()
	{
		return sqrt(this->x * this->x + this->y * this->y + this->z * this->z);
	}

	Vector3f z_vector::Vector3f::Normalize()
	{
		float length = Magnitude();
		if (length != 0.0f) {
			return Vector3f(*this / length);
		}
		return Vector3f(0.0f, 0.0f, 0.0f);
	}

	float Vector3f::Dot(const Vector3f& v1, const Vector3f& v2)
	{
		return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
	}

	Vector3f Vector3f::Product(const Vector3f& v1, const Vector3f& v2)
	{
		float xTerm = v1.y * v2.z - v1.z * v2.y;
		float yTerm = v2.x * v1.z - v1.x * v2.z;
		float zTerm = v1.x * v2.y - v2.x * v1.y;
		return Vector3f(xTerm, yTerm, zTerm);
	}


	void Vector3f::printVec() {
		std::cout << "(x:" << x << " y:" << y  << " z:" << z << ")" << std::endl;
	}

	Vector3f Vector3f::lerp(Vector3f v2, double weight) {
		return Vector3f(
			this->x * (1.0 - weight) + weight * v2.x,
			this->y * (1.0 - weight) + weight * v2.y,
			this->z * (1.0 - weight) + weight * v2.z
		);
	}

